using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;

//Copyright 2009 (c) SocketDemo.

namespace SocketDemo
{
    public partial class MainForm : Form
    {
        #region field

        public delegate void UpdateLogDelegate(string log);
        public delegate void AddClientDelegate(TcpClient client);
        public delegate void RemoveClientDelegate(TcpClient client);

        public UpdateLogDelegate delUpdateLog = null;
        public AddClientDelegate delAddClient = null;
        public RemoveClientDelegate delRemoveClient = null;

        private TcpClient objClient = null;
        private TcpListener objListener = null;

        private List<ClientInfo> lstClientInfo = null;
        private List<TcpClient> lstTcpClient = null;

        #endregion

        #region method

        public MainForm()
        {
            InitializeComponent();

            delUpdateLog = new UpdateLogDelegate(UpdateLog);
            delAddClient = new AddClientDelegate(AddClient);
            delRemoveClient = new RemoveClientDelegate(RemoveClient);
            lstClientInfo = new List<ClientInfo>();
            lstTcpClient = new List<TcpClient>();
            
            grdClientList.AutoGenerateColumns = false;
        }

        private void UpdateLog(string log)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new UpdateLogDelegate(UpdateLog), log);
            }
            else
            {
                txtLog.Text = log + "\r\n" + txtLog.Text;
            }
        }

        private void AddClient(TcpClient client)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new AddClientDelegate(AddClient), client);
            }
            else
            {
                ClientInfo info = new ClientInfo();
                info.ClientHost = client.GetHashCode().ToString();
                info.ConnectTime = DateTime.Now;

                lstClientInfo.Add(info);
                lstTcpClient.Add(client);

                bindingSource1.DataSource = lstClientInfo.ToArray();
                bindingSource1.Sort = "ConnectTime";

                LogHelper.ShowLog("Add Client\t" + info.ClientHost +
                    "\t Client List count:" + lstTcpClient.Count.ToString());
            }
        }

        private void RemoveClient(TcpClient client)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new RemoveClientDelegate(RemoveClient), client);
            }
            else
            {
                for (int i = 0; i < lstClientInfo.Count; i++)
                {
                    if (lstClientInfo[i].ClientHost == client.GetHashCode().ToString())
                    {
                        lstTcpClient.Remove(client);
                        lstClientInfo.RemoveAt(i);
                        break;
                    }
                }

                if (lstClientInfo.Count < 1)
                {
                    bindingSource1.Clear();
                }
                else
                {
                    bindingSource1.Clear();
                    bindingSource1.DataSource = lstClientInfo;
                }

                LogHelper.ShowLog("Remove Client\t" + client.GetHashCode().ToString() +
                    "\t Client List count:" + lstTcpClient.Count.ToString());
            }
        }

        #endregion

        #region event

        private void MainForm_Load(object sender, EventArgs e)
        {
            UpdateLog("Strat\t\t" + DateTime.Now.ToString());
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            UpdateLog("Shutdown\t\t" + DateTime.Now.ToString());
        }

        private void btnConnectHost_Click(object sender, EventArgs e)
        {
            UpdateLog("Connect Host\t" + DateTime.Now.ToString() + "\t" +
                txtRemoteHost.Text + ":" + txtRemotePort.Text);

            ClientHelper.ConnectSocket(ref objClient, txtRemoteHost.Text,
                int.Parse(txtRemotePort.Text), 
                new AsyncCallback(new ClientHelper().DoReading));
        }

        private void btnCloseConnection_Click(object sender, EventArgs e)
        {
            UpdateLog("Close Connection\t" + DateTime.Now.ToString() + "\t" +
                objClient.GetHashCode().ToString());

            ClientHelper.Close(objClient);
        }

        private void txtSend_Click(object sender, EventArgs e)
        {
            UpdateLog("Send\t\t" + DateTime.Now.ToString() + "\t " +
                objClient.GetHashCode().ToString() + "\t" + txtClientMessage.Text);

            ClientHelper.SendData(objClient, txtClientMessage.Text);
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            UpdateLog("Start Listening\t" + DateTime.Now.ToString() + "\t" +
                txtlistenerPort.Text);

            foreach (TcpClient client in lstTcpClient)
            {
                if (client != null)
                {
                    if (client.GetStream() != null)
                    {
                        client.GetStream().Close();
                    }

                    client.Close();
                }
            }

            lstTcpClient.Clear();
            lstClientInfo.Clear();
            bindingSource1.Clear();

            ListenerHelper.StartListening(ref objListener, int.Parse(txtlistenerPort.Text));
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            UpdateLog("Stop Listening\t" + DateTime.Now.ToString());
            
            foreach (TcpClient client in lstTcpClient)
            {
                if (client != null)
                {
                    if (client.GetStream() != null)
                    {
                        client.GetStream().Close();
                    }

                    client.Close();
                }
            }

            lstTcpClient.Clear();
            lstClientInfo.Clear();
            bindingSource1.Clear();

            ListenerHelper.StopListening(ref objListener);
        }

        private void btnServerSend_Click(object sender, EventArgs e)
        {
            if (this.grdClientList.SelectedRows.Count > 0)
            {
                foreach (TcpClient client in lstTcpClient)
                {
                    if (client.GetHashCode().ToString() ==
                        this.grdClientList.SelectedRows[0].Cells[0].Value.ToString())
                    {
                        UpdateLog("Server Send\t" + DateTime.Now.ToString() + "\t" +
                            client.GetHashCode().ToString() + "\t" + txtServerMessage.Text);

                        ClientHelper.SendData(client, txtServerMessage.Text);

                        break;
                    }
                }
            }
        }


        #endregion

        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Start();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            timer1.Stop();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            ClientHelper.SendData(objClient, DateTime.Now.ToString(
                ));
        }
    }
}